﻿using System;
using System.Collections.Generic;
using System.Linq;
using OpenCvSharp.Internal;

namespace OpenCvSharp;

/// <summary>
/// Pixels are weighted using contrast, saturation and well-exposedness measures, than images are combined using laplacian pyramids.
///
/// The resulting image weight is constructed as weighted average of contrast, saturation and well-exposedness measures.
///
/// The resulting image doesn't require tonemapping and can be converted to 8-bit image by multiplying by 255,
/// but it's recommended to apply gamma correction and/or linear tonemapping.
///
/// For more information see @cite MK07 .
/// </summary>
public sealed class MergeMertens : MergeExposures
{
    private Ptr? ptrObj;

    /// <summary>
    /// Creates instance by MergeMertens*
    /// </summary>
    private MergeMertens(IntPtr p)
    {
        ptrObj = new Ptr(p);
        ptr = ptrObj.Get();
    }

    /// <summary>
    /// Creates the empty model.
    /// </summary>
    /// <returns></returns>
    public static MergeMertens Create()
    {
        var ptr = NativeMethods.photo_createMergeMertens();
        return new MergeMertens(ptr);
    }

    /// <summary>
    /// Short version of process, that doesn't take extra arguments.
    /// </summary>
    /// <param name="src">vector of input images</param>
    /// <param name="dst">result image</param>
    public void Process(IEnumerable<Mat> src, OutputArray dst)
    {
        if (src == null)
            throw new ArgumentNullException(nameof(src));
        if (dst == null)
            throw new ArgumentNullException(nameof(dst));

        dst.ThrowIfNotReady();

        var srcArray = src.Select(s => s.CvPtr).ToArray();

        NativeMethods.photo_MergeMertens_process(ptr, srcArray, srcArray.Length, dst.CvPtr);

        GC.KeepAlive(this);
        GC.KeepAlive(src);
        GC.KeepAlive(srcArray);
        dst.Fix();
    }

    /// <summary>
    /// Releases managed resources
    /// </summary>
    protected override void DisposeManaged()
    {
        ptrObj?.Dispose();
        ptrObj = null;
        base.DisposeManaged();
    }

    private class Ptr : OpenCvSharp.Ptr
    {
        public Ptr(IntPtr ptr) : base(ptr)
        {
        }

        public override IntPtr Get()
        {
            var res = NativeMethods.photo_Ptr_MergeMertens_get(ptr);
            GC.KeepAlive(this);
            return res;
        }

        protected override void DisposeUnmanaged()
        {
            NativeMethods.photo_Ptr_MergeMertens_delete(ptr);
            base.DisposeUnmanaged();
        }
    }
}
